package org.codeanalyzer.report;

import java.io.IOException;
import java.io.PrintStream;
import java.util.Date;

import org.codeanalyzer.model.ApiClass;
import org.codeanalyzer.model.ApiLibrary;
import org.codeanalyzer.model.ApiMethod;
import org.codeanalyzer.model.ApiPackage;

/**
 * Creates *.wiki file with the usage report with the format of Google Code Wiki pages.
 */
class WikiUsageReportBuilder extends UsageReportBuilder
{
    @Override
    public void printReport(ApiLibrary apiLibrary, long elapsedTime, int numOfFiles) {
        String fileName = System.getProperty("report.file", apiLibrary.getName() + ".wiki");
        PrintStream out = null;
        try {
            out = new PrintStream(fileName);

            printTitle(apiLibrary, elapsedTime, numOfFiles, out);
            printSummaryCoverage(apiLibrary, out);
            printDetailedCoverage(apiLibrary, out);

            System.out.println("Report is saved to the file " + fileName);
        }
        catch(IOException e) {
            throw new RuntimeException("Unable to write data to the file " + fileName, e);
        }
        finally {
            if (out != null)
                out.close();
        }
    }

    private void printSummaryCoverage(ApiLibrary apiLibrary, PrintStream out) {
        // || *jdk16 0% 1/157* || || || *0% 6/24800* || *0% 2/3121* ||
        out.println("Summary:");
        out.println("|| *Covered packages* || *Class coverage* || *Method Coverage* ||");
        out.println(String
            .format(
                "|| <font size=\"5\">*%2d%%* %3d/%-3d</font> || <font size=\"5\">*%2d%%* %5d/%-5d</font> || <font size=\"5\">*%2d%%* %5d/%-5d</font> ||",
                apiLibrary.getPackageCoverage(), apiLibrary.getTotalCoveredPackages(), apiLibrary.getTotalPackages(),
                apiLibrary.getClassCoverage(), apiLibrary.getTotalCoveredClasses(), apiLibrary.getTotalClasses(),
                apiLibrary.getMethodCoverage(), apiLibrary.getTotalCoveredMethods(), apiLibrary.getTotalMethods()
            ));
        for(ApiPackage apiPackage : apiLibrary.getPackages())
        {
            if ( !apiPackage.isCovered())
                continue;
            out.println(String.format("|| _%s_ || _%2d%% %5d/%-5d_ || _%2d%% %5d/%-5d_ ||",
                apiPackage.getName(),
                apiPackage.getClassCoverage(), apiPackage.getTotalCoveredClasses(), apiPackage.getTotalClasses(),
                apiPackage.getMethodCoverage(), apiPackage.getTotalCoveredMethods(), apiPackage.getTotalMethods()));
        }
    }

    private void printDetailedCoverage(ApiLibrary apiLibrary, PrintStream out) {
        // || *jdk16 0% 1/157* || || || *0% 6/24800* || *0% 2/3121* ||
        out.println("\nDetailed report:");
        out.println("|| *Covered packages* || *Covered classes* || *Covered methods* || *Method Coverage* || *Class coverage* ||");
        for(ApiPackage apiPackage : apiLibrary.getPackages())
        {
            if ( !apiPackage.isCovered())
                continue;

            // ||_java.lang_ || || || _0% 6/995_ || _2% 2/95_ ||
            out.println(String.format("|| _%s_ || || || _%2d%% %5d/%-5d_ || _%2d%% %5d/%-5d_ ||",
                apiPackage.getName(),
                apiPackage.getClassCoverage(), apiPackage.getTotalCoveredClasses(), apiPackage.getTotalClasses(),
                apiPackage.getMethodCoverage(), apiPackage.getTotalCoveredMethods(), apiPackage.getTotalMethods()));

            for(ApiClass apiClass : apiPackage.getClasses())
            {
                if ( !apiClass.isCovered())
                    continue;

                boolean classAlmostCovered = apiClass.getMethodCoverage() > 70;
                StringBuilder methods = new StringBuilder();
                for(ApiMethod apiMethod : apiClass.getMethods()) {
                    if ( !classAlmostCovered && !apiMethod.isCovered())
                        continue;
                    methods.append(apiMethod.isCovered() ? "" : "-");
                    methods.append(apiMethod.getSimpleName() + "(" + apiMethod.getParameters() + ")");
                    methods.append(" <br> ");
                }
                // || ||Boolean || || 41% 5/12 || ||
                out.println(String.format("|| || %s || %s || || %2d%% %5d/%-5d ||",
                    apiClass.getSimpleName(), methods.toString(),
                    apiClass.getMethodCoverage(), apiClass.getTotalCoveredMethods(), apiClass.getTotalMethods()));
            }
        }
    }

    private void printTitle(ApiLibrary apiLibrary, long elapsedTime, int numOfFiles, PrintStream out) {
        out.println("=== Usage report for API library: " + apiLibrary.getName() + " ===");
        out.println("==== Analyzed " + numOfFiles + " files. Elapsed time: " + elapsedTime + "ms. Report date: "
            + new Date() + " ====");
        out.println("----");
    }
}
